#include "relay.h"
#include "fsm.h"
#include <pthread.h>
#include <stdlib.h>
#include <errno.h>

//全局任务数组
static struct job_st *jobs[JOB_MAX];
//保护任务数组的互斥量
static pthread_mutex_t job_mutex = PTHREAD_MUTEX_INITIALIZER;
//单次初始化变量
static pthread_once_t job_once = PTHREAD_ONCE_INIT;
static pthread_t bg;
static pthread_once_t init_once = PTHREAD_ONCE_INIT;

struct job_st
{
    int job_state;
    int fd1;
    int fd2;
    fsm_st fsm12;
    fsm_st fsm21;
};


void relay_wait() {
    pthread_join(bg, NULL);
}

static void *handler(void *p)
{

#define NSEC_TO_SLEEP 100

    struct timespec remaining, request;
    remaining.tv_nsec = NSEC_TO_SLEEP;
    request.tv_nsec = NSEC_TO_SLEEP;
    while (1)
    {
        pthread_mutex_lock(&job_mutex);
        for (int i = 0; i < JOB_MAX; i++)
        {
            if (jobs[i] == NULL)
                continue;

            if (jobs[i]->job_state != STATE_RUNNING)
            {
                continue;
            }

            if (fsm_state(jobs[i]->fsm12) != STATE_T)
            {
                fsm_drive(jobs[i]->fsm12);
            }

            if (fsm_state(jobs[i]->fsm21) != STATE_T)
            {
                fsm_drive(jobs[i]->fsm21);
            }

            if (fsm_state(jobs[i]->fsm12) == STATE_T && fsm_state(jobs[i]->fsm21) == STATE_T)
            {
                jobs[i]->job_state = STATE_OVER;
            }
        }
        pthread_mutex_unlock(&job_mutex);

        nanosleep(&request, NULL);
    }
}

void module_load()
{
    pthread_create(&bg, NULL, handler, NULL);
}


static int get_free_pos_unlocked()
{
    for (int i = 0; i < JOB_MAX; i++)
    {
        if (jobs[i] == NULL)
            return i;
    }
    return -1;
}

int relay_addjob(int fd1, int fd2)
{
    pthread_once(&init_once, module_load);

    pthread_mutex_lock(&job_mutex);
    int pos = get_free_pos_unlocked();

    if (pos < 0)
    {
        pthread_mutex_unlock(&job_mutex);
        return -ENOSPC;
    }

    struct job_st *job =
        malloc(sizeof(struct job_st));

    if (job == NULL)
    {
        pthread_mutex_unlock(&job_mutex);
        return -ENOMEM;
    }

    jobs[pos] = job;
    pthread_mutex_unlock(&job_mutex);

    job->fd1 = fd1;
    job->fd2 = fd2;
    job->job_state = STATE_RUNNING;
    job->fsm12 = fsm_new(fd1, fd2);
    job->fsm21 = fsm_new(fd2, fd1);

    return pos;
}